<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>音频可视化</title>
    <style>
        canvas {
            border: 1px solid black;
        }
    </style>
</head>
<body>
<h1>音频可视化</h1>
<input type="file" accept="audio/*" onchange="loadAudio()"><br>
<canvas id="canvas" width="800" height="200"></canvas>

<script>
    // 初始化变量
    let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
    let analyser = audioCtx.createAnalyser();
    let source;
    let dataArray;
    let bufferLength;

    // 加载音频文件
    function loadAudio() {
        let file = document.querySelector('input[type=file]').files[0];
        let reader = new FileReader();
        reader.onload = function(e) {
            // 读取音频数据
            audioCtx.decodeAudioData(e.target.result).then(function(decodedData) {
                // 创建音频源
                source = audioCtx.createBufferSource();
                source.buffer = decodedData;
                // 连接音频源和分析器
                source.connect(analyser);
                analyser.connect(audioCtx.destination);
                // 获取分析器的数据
                analyser.fftSize = 256;
                bufferLength = analyser.frequencyBinCount;
                dataArray = new Uint8Array(bufferLength);
                // 播放音频
                source.start();
                // 开始绘制可视化效果
                draw();
            });
        }
        reader.readAsArrayBuffer(file);
    }

    // 绘制可视化效果
    function draw() {
        // 获取画布
        let canvas = document.getElementById("canvas");
        let canvasCtx = canvas.getContext("2d");
        // 清空画布
        canvasCtx.clearRect(0, 0, canvas.width, canvas.height);
        // 获取分析器的数据
        analyser.getByteFrequencyData(dataArray);
        // 绘制可视化效果
        let barWidth = (canvas.width / bufferLength) * 2.5;
        let barHeight;
        let x = 0;
        for(let i = 0; i < bufferLength; i++) {
            barHeight = dataArray[i];
            canvasCtx.fillStyle = 'rgb(' + (barHeight+100) + ',50,50)';
            canvasCtx.fillRect(x,canvas.height-barHeight/2,barWidth,barHeight/2);
            x += barWidth + 1;
        }
        // 循环绘制
        requestAnimationFrame(draw);
    }
</script>
</body>
</html>
